﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Gnosis.Babel;

namespace Gnosis.SQLite
{
    public abstract class Expression
        : IExpression
    {
        protected Expression()
            : this(string.Empty, string.Empty, string.Empty, new List<IExpression>())
        {
        }

        protected Expression(string prefix)
            : this(prefix, string.Empty, string.Empty, new List<IExpression>())
        {
        }

        protected Expression(IExpression child)
            : this(string.Empty, string.Empty, string.Empty, new List<IExpression> { child })
        {
        }

        protected Expression(IList<IExpression> children)
            : this(string.Empty, string.Empty, string.Empty, children)
        {
        }

        protected Expression(string prefix, IExpression child)
            : this(prefix, string.Empty, string.Empty, new List<IExpression> { child })
        {
        }

        protected Expression(string prefix, IList<IExpression> children)
            : this(prefix, string.Empty, string.Empty, children)
        {
        }

        protected Expression(string infix, IExpression left, IExpression right)
            : this(string.Empty, infix, string.Empty, new List<IExpression> { left, right })
        {
        }

        protected Expression(string prefix, string postfix, IExpression child)
            : this(prefix, string.Empty, postfix, new List<IExpression> { child })
        {
        }

        protected Expression(string prefix, string postfix, IList<IExpression> children)
            : this(prefix, string.Empty, postfix, children)
        {
        }

        protected Expression(string prefix, string infix, string postfix)
            : this(prefix, infix, postfix, new List<IExpression>())
        {
        }

        protected Expression(string prefix, string infix, string postfix, IExpression child)
            : this(prefix, infix, postfix, new List<IExpression> { child })
        {
        }

        protected Expression(string prefix, string infix, string postfix, IList<IExpression> children)
        {
            _prefix = prefix ?? string.Empty;
            _infix = infix ?? string.Empty;
            _postfix = postfix ?? string.Empty;
            _children = children ?? new List<IExpression>();
        }

        private readonly string _prefix;
        private readonly string _infix;
        private readonly string _postfix;
        private readonly IList<IExpression> _children;

        protected string Prefix
        {
            get { return _prefix; }
        }

        protected string Infix
        {
            get { return _infix; }
        }

        protected string Postfix
        {
            get { return _postfix; }
        }

        protected void AddChildren<T>(IEnumerable<T> children)
            where T : IExpression
        {
            foreach (T child in children)
                AddChild(child);
        }

        protected void AddChild(IExpression child)
        {
            _children.Add(child);
        }

        protected void RemoveChild(IExpression child)
        {
            _children.Remove(child);
        }

        protected virtual IList<IExpression> GetChildren()
        {
            return _children;
        }

        #region IExpression Members

        public IEnumerable<IExpression> Children
        {
            get { return GetChildren(); }
        }

        #endregion

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder(string.Empty);
            const string format = "{0}";

            IList<IExpression> children = GetChildren();

            sb.AppendFormat(format, _prefix);

            for (int i=0; i < children.Count; i++ )
            {
                sb.Append(children[i].ToString());
                
                if (i < children.Count-1)
                {
                    sb.AppendFormat(format, _infix);
                }
            }

            sb.AppendFormat(format, _postfix);

            return sb.ToString();
        }
    }
}
